import UIKit

enum DWSplitDownloadError: Error {
    ///下载中
    case downloading
    ///不是HTTPURLResponse类型
    case notHTTPURLResponse
    ///throws错误
    case `throws`(Error)
    ///文件保存失败
    case fileCompound
    ///状态码错误
    case statusCode(Int)
    ///下载错误
    case download(Error)
}

class DWSplitInfoOperation: Operation {
    var resultBlock: ((Int64) -> ())?
    private (set) var error: DWSplitDownloadError?
    private var task: URLSessionDownloadTask!
    private var taskFinished: Bool = true {
        willSet {
            if taskFinished != newValue {
                willChangeValue(forKey: "isFinished")
            }
        }
        didSet {
            if taskFinished != oldValue {
                didChangeValue(forKey: "isFinished")
            }
        }
    }
    private var taskExecuting: Bool = false {
        willSet {
            if taskExecuting != newValue {
                willChangeValue(forKey: "isExecuting")
            }
        }
        didSet {
            if taskExecuting != oldValue {
                didChangeValue(forKey: "isExecuting")
            }
        }
    }
    
    override var isFinished: Bool {
        return taskFinished
    }
    
    override var isExecuting: Bool {
        return taskExecuting
    }
    
    override var isAsynchronous: Bool {
        return true
    }
    
    init(url: URL, resultBlock: ((Int64) -> ())? = nil) {
        super.init()
        var request = URLRequest(url: url)
        request.timeoutInterval = 300
        request.addValue("bytes=0-1", forHTTPHeaderField: "Range")
        let session: URLSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
        task = session.downloadTask(with: request)
        self.resultBlock = resultBlock
    }
    
}

extension DWSplitInfoOperation {
    override func start() {
        autoreleasepool {
            if isCancelled {
                taskFinished = true
                taskExecuting = false
            }else {
                taskFinished = false
                taskExecuting = true
                startTask()
            }
        }
    }
    
    override func cancel() {
        if (isExecuting) {
            task.cancel()
        }
        super.cancel()
    }
    
}

private extension DWSplitInfoOperation {
    
    func startTask() {
        task.resume()
    }
    
    func complete(_ error: DWSplitDownloadError? = nil) {
        self.error = error
        taskFinished = true
        taskExecuting = false
    }
}

extension DWSplitInfoOperation: URLSessionDelegate, URLSessionDownloadDelegate {
    
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        let headerDic = (task.response as! HTTPURLResponse).allHeaderFields
        let rangeKeyArray : [String] = ["Content-Range", "Content-range", "content-Range", "content-range"]
        var rangeValue : String?
        for rangeKey in rangeKeyArray {
            if let _rangeValue = headerDic[rangeKey] as? String {
                rangeValue = _rangeValue
                break
            }
        }
        guard let rangeStr = rangeValue else {
            resultBlock?(-1)
            complete(.notHTTPURLResponse)
            return }
        let lengthStr = rangeStr.components(separatedBy: "/")[1]
        resultBlock?(Int64(lengthStr) ?? 0)
        complete()
    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        session.invalidateAndCancel()
        guard let response = task.response as? HTTPURLResponse else {
            resultBlock?(-1)
            complete(.notHTTPURLResponse)
            return
        }
        if let error = error {
            resultBlock?(-1)
            complete(.download(error))
        }else if (response.statusCode == 200 || response.statusCode == 206) {
            complete()
        }else {
            resultBlock?(-1)
            complete(.statusCode(response.statusCode))
        }
    }
    
}

